package com.bitcola.chainserver.chain.eth;


import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.bitcola.chainserver.util.AESUtil;
import com.bitcola.chainserver.init.GlobalChain;
import com.bitcola.chainserver.util.HttpClientUtils;
import com.bitcola.security.common.msg.ColaChainWithdrawResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.*;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/*
 * @author:wx
 * @description:
 * @create:2018-10-20  15:34
 */
@Log4j2
@Service
public class EthCore {

    static String WEB3_ADDRESS="http://47.241.11.20/infura/v3/e326dd0bde4c499494c67c9cd6b7ee46";
     static String gasPriceUrl="https://ethgasstation.info/json/ethgasAPI.json";


     static String []web3Address={
             "http://47.241.11.20/infura/v3/e8ebc5e4ab8743d2b4b395a67ad3ce73",
     "http://47.241.11.20/infura/v3/2c8ce992d735445ea76176729912599d","http://47.241.11.20/infura/v3/3564fa17fa604f538ddae756fb4b6762",
             "http://47.241.11.20/infura/v3/f3d6a0909f6d47faa440f810a9c3ab5d","http://47.241.11.20/infura/v3/357e6a46aaea427e90be0fad75c42037",
             "http://47.241.11.20/infura/v3/b8af968cc0fb4f3ea420cbd8700e5dd2","http://47.241.11.20/infura/v3/4218ebdb2f6744be904fe46a922b660c"
             ,"http://47.241.11.20/infura/v3/c07750aeb4494d7694b9465121217a9e","http://47.241.11.20/infura/v3/62af14ba73c44d599a3077e7bdfa7bdf",
             "http://47.241.11.20/infura/v3/f4b3e91a1e4d4c7e9ed5fd139fbc6086","http://47.241.11.20/infura/v3/17f49c5b11a447f594198077d4fb7f4f",
             "http://47.241.11.20/infura/v3/9ca69b5aaf6a49e8b4de4b87901aef66","http://47.241.11.20/infura/v3/1e54136ff23e4455a85953c1f042d6c9",
             "http://47.241.11.20/infura/v3/19dbee8f1b7c4c65bf0a38b065f7c593","http://47.241.11.20/infura/v3/5459856316574230a3e9c81b0334b28d",
             "http://47.241.11.20/infura/v3/e358c3e2e72b4377b360d1598b79bd66","http://47.241.11.20/infura/v3/e326dd0bde4c499494c67c9cd6b7ee46",
             "http://47.241.11.20/infura/v3/ae94407f250e4fec8b2fd9fcbb2e03fc","http://47.241.11.20/infura/v3/deb9776c04b14450bbd8c0d2febfc1b2",
             "http://47.241.11.20/infura/v3/2a255fe1305d4a56b05035190615cb38","http://47.241.11.20/infura/v3/593ad7c00d0049d5af00303b1a7f6907",
             "http://47.241.11.20/infura/v3/3b1f84272b8443b2a94baa291422186c","http://47.241.11.20/infura/v3/206e6f3424f348eeb8b9387d5283a5d8",
             "http://47.241.11.20/infura/v3/bcc6214da1314f038436ae8a12cc473e","http://47.241.11.20/infura/v3/7ef1faf3cff7449f9bb4ed02e1bb65e5",
             "http://47.241.11.20/infura/v3/b19591a7596a4fb2a49114d692bb263d","http://47.241.11.20/infura/v3/80d8dfc2072c4d6c88e83885c088f0f9",
             "http://47.241.11.20/infura/v3/240959f013674c68bff6aa80e55c7ec3"
     };

     static      volatile long start=0;
    public  static Web3j getWeb3j(){
        if(start==0) start=System.currentTimeMillis();
        int i=integer.incrementAndGet();
        totalCount.incrementAndGet();
        if(i%500==0) {

            long period = System.currentTimeMillis() - start;
            log.info("调用次数: " + i + "  总共调用次数: " + totalCount.intValue() + " 历时: "+period/1000+"秒"+",预计24小时调用次数: "+(totalCount.intValue()/(period/1000))*60*60*24+"  " +
                    " 当前api个数: "+web3j.length+"  平均每个api24小时预计负载: "+(totalCount.intValue()/(period/1000))*60*60*24/web3j.length);
        }
        synchronized (integer) {
            if (i > 100000) integer = new AtomicInteger(1);
            i=i%web3Address.length;
        }
        return web3j[i];
    }
     public static String BITCOLA_ADDRESS="0x360e4186124a4deC75BE0b4Df632bF3Cc16668F4";
     public static String hotKey="p/jCVcGq9Rid7Ui5FIfTSXTentI9m1S7sHRchcCsqU6xSi8O7rfxo5q0d/PqH+TeNPLMJtMMClQGXEjFcHzl7RntFu60V93MoOSXt0dDBlY=";
      public static volatile BigInteger GAS_PRICE = Convert.toWei("10", Convert.Unit.GWEI).toBigInteger();


      public static BigInteger getGasPrice()
      {
          return GAS_PRICE;

      }


    private static  Web3j[] web3j=new Web3j[web3Address.length];
      static AtomicInteger integer=new AtomicInteger(1);

      static AtomicInteger totalCount=new AtomicInteger(1);

    static Timer timer=new Timer();

    static {
        for (int i = 0; i < web3Address.length; i++) {
            web3j[i]=Web3j.build(new HttpService(web3Address[i]));

        }
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    String content= HttpClientUtils.get(gasPriceUrl);
                    JSONObject jsonObject=JSONObject.parseObject(content);
//                    GAS_PRICE= BigInteger.valueOf(jsonObject.getBigDecimal("average").divide(BigDecimal.TEN).intValue()+3);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },1000,20*1000);
    }


    /**
     * 查看此 hash 之前的余额和之后的余额是否相差当前数值
     * @param hash
     * @return
     */
    public static boolean depositSuccess(String hash) throws IOException{
        Transaction transaction = getTransactionByHash(hash);
        BigInteger blockNumber = transaction.getBlockNumber();
        String contract = getContract(transaction);
        BigInteger number = getNumber(transaction);
        // 获得这个区块之前的 to 地址的余额,再获当前区块余额,比较
        BigInteger sub;
        if (StringUtils.isNotBlank(contract)){
            String toAddress = getTokenToAddress(transaction.getInput());
            BigInteger oldTokenBalance = getTokenBalance(toAddress, contract, DefaultBlockParameter.valueOf(blockNumber.subtract(BigInteger.ONE)));
            BigInteger tokenBalance = getTokenBalance(toAddress, contract, DefaultBlockParameter.valueOf(blockNumber));
            sub = tokenBalance.subtract(oldTokenBalance);
        } else {
            String toAddress = transaction.getTo();
            BigInteger oldTokenBalance = getEthBalance(toAddress, DefaultBlockParameter.valueOf(blockNumber.subtract(BigInteger.ONE)));
            BigInteger tokenBalance = getEthBalance(toAddress, DefaultBlockParameter.valueOf(blockNumber));
            sub = tokenBalance.subtract(oldTokenBalance);
        }
        return true;

    }


    public static Transaction getTransactionByHash(String hash) throws IOException{
        return getWeb3j().ethGetTransactionByHash(hash).send().getResult();
    }


    public static Credentials newAccount(String password) throws Exception{
        String path = GlobalChain.JAR_PATH+"/eth/key";
        File file = new File(path);
        if (!file.exists()){
            file.mkdirs();
        }
        String fileName = WalletUtils.generateNewWalletFile(password, file, false);
        return WalletUtils.loadCredentials(password, path+"/"+fileName);
    }



    public static ColaChainWithdrawResponse transaction(String toAddress, BigInteger number, String privateKey, BigInteger nonce){
        Web3j web3j = getWeb3j();

        ColaChainWithdrawResponse response = new ColaChainWithdrawResponse();
        try {
            // 验证余额
            Credentials credentials = Credentials.create(privateKey);
            BigInteger balance = getEthBalance(credentials.getAddress());
            if (number.compareTo(balance) >= 0){
                response.setSuccess(false);
                response.setErrMessage("ETH余额不足");
                return response;
            }
            // 获取个人钱包
            //Credentials credentials = loadCredentials(fromAddress,password);
            EthSendTransaction ethSendTransaction = null;
            // 设置手续费 和交易数量
            BigInteger GAS_PRICE = Convert.toWei(getGasPrice().toString(), Convert.Unit.GWEI).toBigInteger();
            BigInteger GAS_LIMIT = BigInteger.valueOf(210000l);

            // 创建交易
            RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
                    nonce, GAS_PRICE,GAS_LIMIT, toAddress,number);

            // 对交易签名
            byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
            String hexValue = Numeric.toHexString(signedMessage);

            // 发送交易到链上
            ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
            if (ethSendTransaction.hasError()) {
                response.setSuccess(false);
                response.setErrMessage(ethSendTransaction.getError().getMessage());
            } else {
                String transactionHash = ethSendTransaction.getTransactionHash();
                response.setSuccess(true);
                response.setHash(transactionHash);
                response.setFee(getEthDecimal(GAS_PRICE.multiply(GAS_LIMIT)));
                return response;
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            response.setSuccess(false);
            response.setErrMessage(e.getLocalizedMessage());
        }
        return response;
    }

    /**
     * 默认手续费
     * @param toAddress
     * @param number         eth 数量
     * @return
     */
    public static      ColaChainWithdrawResponse  transaction2(String toAddress,BigDecimal number,String privateKey){
            Web3j web3j = getWeb3j();
        // 获取个人钱包
        //Credentials credentials = loadCredentials(fromAddress,password);
        Credentials credentials = Credentials.create(privateKey);
        ColaChainWithdrawResponse response = new ColaChainWithdrawResponse();
        try {
            log.info("== 正在转移手续费:");

            TransactionReceipt transactionReceipt = Transfer.sendFunds(
                    web3j, credentials, toAddress,
                    number, Convert.Unit.ETHER).sendAsync().get();
            response.setSuccess(true);
            response.setHash(transactionReceipt.getTransactionHash());
            response.setFee(getEthDecimal(transactionReceipt.getGasUsed()));
            log.info("== 转移手续费成功:");

        } catch (Exception e) {
            response.setSuccess(false);
            log.info("== 转移手续费失败:");

            response.setErrMessage(e.getMessage());
            log.error(e.getMessage(),e);
        }
        return response;
    }


    /**
     * ETH token转账
     * @param toAddress   到这个地址
     * @param number        数量      eth 数量
     * @param contractAddress   合约地址
     * @return
     */
    public static ColaChainWithdrawResponse transactionToken(String toAddress,BigInteger number,String contractAddress,String privateKey,BigInteger nonce){
        Web3j web3j = getWeb3j();
        ColaChainWithdrawResponse response = new ColaChainWithdrawResponse();
        // 获取个人钱包
        //Credentials credentials = loadCredentials(fromAddress,password);
        Credentials credentials = Credentials.create(privateKey);
        EthSendTransaction ethSendTransaction = null;
        try {
            BigInteger tokenBalance = getTokenBalance(credentials.getAddress(), contractAddress);
            if (tokenBalance.compareTo(number) < 0){
                response.setSuccess(false);
                response.setErrMessage("ETH token 余额不足");
                return response;
            }
            // 设置手续费 和交易数量
            BigInteger GAS_PRICE = Convert.toWei(getGasPrice().toString(), Convert.Unit.GWEI).toBigInteger();
            BigInteger GAS_LIMIT = BigInteger.valueOf(60000L);

            Function function = new Function(
                    "transfer",
                    Arrays.asList(new Address(toAddress), new Uint256(number)),
                    Arrays.asList(new TypeReference<Type>() {
                    }));
            String encodedFunction = FunctionEncoder.encode(function);
            // 创建交易
            RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, GAS_PRICE,
                    GAS_LIMIT, contractAddress, encodedFunction);

            // 对交易签名
            byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
            String hexValue = Numeric.toHexString(signedMessage);

            // 发送交易到链上
            ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
            // 解析返回的结果

            if (ethSendTransaction.hasError()) {
                response.setSuccess(false);
                response.setErrMessage(ethSendTransaction.getError().getMessage());
            } else {
                String transactionHash = ethSendTransaction.getTransactionHash();
                response.setSuccess(true);
                response.setHash(transactionHash);
                response.setFee(getEthDecimal(GAS_PRICE.multiply(GAS_LIMIT)));
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            response.setSuccess(false);
            response.setErrMessage(e.getLocalizedMessage());
        }
        return response;
    }

    public static BigInteger getTokenBalance(String address,String contract) throws IOException{
        return getTokenBalance(address,contract,DefaultBlockParameterName.LATEST);
    }
    public static  BigInteger getTokenBalance(String address,String contract,DefaultBlockParameter blockNumber) throws IOException {

        try {
            Function function = new Function("balanceOf",
                    Arrays.asList(new Address(address)),
                    Arrays.asList(new TypeReference<Address>() {
                    })
            );
            String encodedFunction = FunctionEncoder.encode(function);
            String value = EthCore.getWeb3j().ethCall(org.web3j.protocol.core.methods.request.Transaction.
                    createEthCallTransaction(address, contract, encodedFunction), blockNumber)
                    .send().getValue();
            return Numeric.decodeQuantity(value);

        }catch (Throwable e){
            String url=String.format("https://api-cn.etherscan.com/api?module=account&action=tokenbalance&contractaddress=%s&address=%s&tag=latest&apikey=IC1ENVWBZMNGGA81BFWENINTGF3R5DYBXC",contract,address);
            String content=null;
            try {
                content= HttpClientUtils.get(url);
            } catch (Exception ex) {
                ex.printStackTrace();
                throw e;

            }
            if(content==null) return BigInteger.ZERO;

            List<String>result=new ArrayList<>();
            var value= JSONObject.parseObject(content).getBigInteger("result");
            return value;
        }

    }
//    public static BigInteger getTokenBalance(Web3j web3j, String fromAddress, String contractAddress) {
//
//        String methodName = "balanceOf";
//        List<Type> inputParameters = new ArrayList<>();
//        List<TypeReference<?>> outputParameters = new ArrayList<>();
//        Address address = new Address(fromAddress);
//        inputParameters.add(address);
//
//        TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
//        };
//        outputParameters.add(typeReference);
//        Function function = new Function(methodName, inputParameters, outputParameters);
//        String data = FunctionEncoder.encode(function);
//        Transaction transaction = org.web3j.protocol.core.methods.request.Transaction.
//                createEthCallTransaction(address, contractAddress, data);
//
//        EthCall ethCall;
//        BigInteger balanceValue = BigInteger.ZERO;
//        try {
//            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
//            List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
//            balanceValue = (BigInteger) results.get(0).getValue();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return balanceValue;
//    }



    public static BigInteger getEthBalance(String address, DefaultBlockParameter blockNumber) throws IOException{
        return getWeb3j().ethGetBalance(address,blockNumber).send().getBalance();
    }
    public static BigInteger getEthBalance(String address) throws IOException{
        return getEthBalance(address,DefaultBlockParameterName.LATEST);
    }


    /**
     * 获取 input 中的数量
     * @param input
     * @return
     */
    private static BigInteger getTokenNumber(String input){
        if (input.length() == 138){
            String number = input.substring(74);
            return new BigInteger(number,16);
        }
        return null;
    }


    /**
     * 获取 input 中的收款地址
     * @return
     */
    private static String getTokenToAddress(String input){
        return  "0x"+input.substring(34, 74);
    }

    /**
     * BigDecimal  --> BigInteger
     * @param number
     * @param unit 单位,默认是 18
     * @return
     */
    public static BigInteger getEthInteger(BigDecimal number,int unit){
        return number.multiply(BigDecimal.TEN.pow(unit)).toBigInteger();
    }
    public static BigInteger getEthInteger(BigDecimal number){
        return getEthInteger(number,18);
    }

    /**
     * BigInteger  --> BigDecimal
     * @param number
     * @param unit 单位,默认是 18
     * @return
     */
    public static BigDecimal getEthDecimal(BigInteger number,int unit){
        BigDecimal factor = BigDecimal.TEN.pow(unit);
        return new BigDecimal(number.toString()).divide(factor);
    }
    public static BigDecimal getEthDecimal(BigInteger number){
        return getEthDecimal(number,18);
    }



    public static synchronized BigInteger getEthNonce(String address) throws Exception{
        EthGetTransactionCount ethGetTransactionCount = getWeb3j().ethGetTransactionCount(
                address, DefaultBlockParameterName.LATEST).sendAsync().get();
        return ethGetTransactionCount.getTransactionCount();
    }


    public static boolean checkAddress(String address) {
        if (StringUtils.isBlank(address)) return false;
        address = address.toLowerCase();
        if (address.length() != 42) return false;
        try {
            Numeric.decodeQuantity(address);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static String getToAddress(Transaction transaction){
        String input = transaction.getInput();
        if (input.length() == 138){
            return getTokenToAddress(input);
        } else if (input.equals("0x")){
            return transaction.getTo();
        }
        return null;
    }
    public static BigInteger getNumber(Transaction transaction){
        String input = transaction.getInput();
        if (input.length() == 138){
            return getTokenNumber(input);
        } else if (input.equals("0x")){
            return transaction.getValue();
        }
        return null;
    }
    public static boolean isTokenTransaction(Transaction transaction){
        return transaction.getInput().length() == 138 ;
    }
    public static String getContract(Transaction transaction){
        if (isTokenTransaction(transaction)) return transaction.getTo();
        return null;
    }


    static long end;

    static {
        try {
            end = getWeb3j().ethBlockNumber().send().getBlockNumber().longValue();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static long pre=0;
    static Set<String>sets=new HashSet<>();
    static String finalHash;
    public static List<String>getAddress(String address,Long page ,int size,String sort){
        String str = "yyy-MM-dd HH:mm:ss";
        SimpleDateFormat sdf = new SimpleDateFormat(str);
        if(page*size>=10000){
            page=1l;
            start=pre+1;
        }
        String url=String.format("https://api-cn.etherscan.com/api?module=account&action=tokentx&address=%s&startblock=%s&endblock=" +
                "%s&page=%s&offset=%s&sort=%s&apikey=IC1ENVWBZMNGGA81BFWENINTGF3R5DYBXC",address,start,end,page,size,sort);
        String content=null;
        try {
            content= HttpClientUtils.get(url);
        } catch (Exception e) {
            e.printStackTrace();
            page--;
            return new ArrayList<>();
        }


        if(content==null) return null;
        List<String>result=new ArrayList<>();
         var array= JSONObject.parseObject(content).getJSONArray("result");
         if(array==null) return null;


         if(array.size()==0){
             start=pre+1;
         }
        for(Object object:array){
             JSONObject jsonObject= (JSONObject) object;
             String hash=jsonObject.getString("hash");
             String from=jsonObject.getString("from");
             String to=jsonObject.getString("to");
             finalHash=hash;

             long number=jsonObject.getLong("blockNumber");
             long time=jsonObject.getLong("timeStamp");
            if(sets.contains(hash)){
                start=pre+1;
                break;
            }else{
                sets.add(hash);
            }
            pre=number;

             if(to.equals(address)){
                 System.out.println("hash+"+hash);
                 System.out.println(sdf.format(new Date(time*1000)));
                 result.add(from);
             }else if(!from.equals(address)&&!to.equals(address)){
                 otherAddress.add(to);

             }
         }
         return result;

    }
    static ExecutorService service=Executors.newFixedThreadPool(30);
    static Set<String>otherAddress=new HashSet<>();

    public static void main1(String[] args) {











    }



    /**
     * 生成一个账号
     * @throws Exception
     */
    private static void createAccount(String passowrd,String encoderPassword) throws Exception{
        GlobalChain.JAR_PATH = "/Users/qiuqiu/mywork/my";
        Credentials credentials = newAccount(passowrd);
        ECKeyPair ecKeyPair = credentials.getEcKeyPair();
        System.out.println("地址: "+credentials.getAddress());
        BigInteger privateKey = ecKeyPair.getPrivateKey();
        BigInteger publicKey = ecKeyPair.getPublicKey();
        String privateKeyDecode = Numeric.toHexStringWithPrefix(privateKey);
        System.out.println("公钥: "+Numeric.toHexStringWithPrefix(publicKey));
        System.out.println("私钥: "+AESUtil.encrypt(privateKeyDecode, encoderPassword));
    }


    /**
     * 发行 token
     *
     * @param data https://www.jianshu.com/p/9e6c17c47efb  // 教程地址 (直接看我下面写的教程即可)
     *             http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.21+commit.dfe3193c.js // 在线编辑器
     *             https://github.com/ConsenSys/Tokens/tree/master/contracts/eip20 // 合约地址
     *
     *   发行步骤 1 在线编译合约代码 (需要翻墙),获得 abi 和 bytecode
     *                编译成功后点击右边 Details ,在弹出框中找到第五个大块 里面有 abi -> WEB3DEPLOY (5行) , bytecode -> WEB3DEPLOY (13行)
     *
     *           2 下载官方节点 https://geth.ethereum.org/downloads/
     *
     *           3  # 导入有eth的账户，要用这个账户来部署合约呢,private.key 为私钥转 16 进制文本文件,这个账号保证有 0.05 ETH及以上
     *              ./geth account import private.key
     *              # 启动孤立的节点
     *              ./geth --nodiscover console --rpc --rpcapi 'web3,eth,debug' --rpcport 8545 --rpccorsdomain '*' #
     *              # 查看导入的账户是第几位
     *              > eth.accounts
     *
     *           4 依次在 eth 控制台运行下面代码
     *
     *
     *      > var abi = [{.....}]  // 编译后的合约 WEB3DEPLOY (5行)
     *      > var bytecode = '0x6060604xxxxxxb0029' // 编译后的data  WEB3DEPLOY (13行)
     *      > var c = eth.contract(abi)
     *      > var cData = {from:eth.accounts[1], data:bytecode} //部署账户
     *      > var dcode = c.new.getData('100000000', 'tokenName', 18, 'SYMBOL', cData) // token数量,名字,精度(一般是 18 位),代号
     *      > decode
     *
     *           5 将获得的 decode 传入以下方法的 data 值运行
     *
     * @param address
     * @param privateKey
     * @throws Exception
     */
//    public static void createToken(String data,String address,String privateKey) throws Exception{
//        Credentials credentials = Credentials.create(privateKey);
//
//        // 设置手续费 和交易数量
//        BigInteger GAS_PRICE = Convert.toWei("9", Convert.Unit.GWEI).toBigInteger();
//        BigInteger GAS_LIMIT = BigInteger.valueOf(5000000L);
//
//        // 创建交易
//        RawTransaction rawTransaction = RawTransaction.createTransaction(
//                getEthNonce(address), GAS_PRICE,GAS_LIMIT, null,data);
//
//        // 对交易签名
//        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
//        String hexValue = Numeric.toHexString(signedMessage);
//
//        // 发送交易到链上
//        EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).send();
//        System.out.println(JSONObject.toJSONString(ethSendTransaction));
//    }


}
